#pragma once

#include <memory>
#include <functional>

#include "ScriptDelegate.h"
#include "Containers/Vector.h"
#include "Containers/WeakObjectPtr.h"

#include "Containers/Any.h"

#include "Object/Object.h"

#include "Reflection/Function.h"


class IScriptFunction
{
public:
    enum class EType
    {
        ReflectedFunction,  // a CFuntion
        STDFunction,        // a std::function
        RawStaticFunction,        // a raw static function pointer
        RObjectMember, // a member function of a RObject
    };
    virtual IScriptFunction::EType GetType() const =0;
    
    //can static_cast to CNativeInvoker
    virtual bool SupportNativeInvoke() const { return true; }

    virtual ~IScriptFunction()=default;
    virtual CAny Invoke(const TVector<CAny>& InArguments)=0;
    virtual SDecoratedType GetReturnType() const =0;
    virtual TVector<SDecoratedType> GetParameterTypes() const =0;
    virtual uint64_t GetHashCode() const =0;
    virtual bool IsEqual(const IScriptFunction * Other) const =0;
    virtual bool IsValid() const { return true; }
};

template<typename ReturnType, typename ...Args>
requires (sizeof...(Args) <= 5)
class CNativeInvoker;

template<typename ReturnType>
class CNativeInvoker<ReturnType()>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke() = 0;
};

template<typename ReturnType, typename Arg0>
class CNativeInvoker<ReturnType(Arg0)>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke(Arg0) = 0;
};

template<typename ReturnType, typename Arg0, typename Arg1>
class CNativeInvoker<ReturnType(Arg0,Arg1)>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke(Arg0,Arg1) = 0;
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2>
class CNativeInvoker<ReturnType(Arg0,Arg1,Arg2)>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke(Arg0,Arg1,Arg2) = 0;
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3)>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke(Arg0,Arg1,Arg2,Arg3) = 0;
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)>:public IScriptFunction
{
public:
    virtual ReturnType NativeInvoke(Arg0,Arg1,Arg2,Arg3,Arg4) = 0;
};

template<typename ReturnType, typename ...Args>
requires (sizeof...(Args) <= 5)
class CRawStaticFunctionForScript;

template<typename ReturnType>
class CRawStaticFunctionForScript<ReturnType()> : public CNativeInvoker<ReturnType()>
{
public:
    using FunctionType=ReturnType(*)();
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke() override
    {
        return Function();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        return CAny(Function());
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<>
class CRawStaticFunctionForScript<void()>  : public CNativeInvoker<void()>
{
public:
    using FunctionType=void(*)();
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke() override
    {
        Function();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        Function();
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename ReturnType, typename Arg0>
class CRawStaticFunctionForScript<ReturnType(Arg0)> : public CNativeInvoker<ReturnType(Arg0)>
{
public:
    using FunctionType=ReturnType(*)(Arg0);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0) override
    {
        return Function(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename Arg0>
class CRawStaticFunctionForScript<void(Arg0)> : public CNativeInvoker<void(Arg0)>
{
public:
    using FunctionType=void(*)(Arg0);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0) override
    {
        Function(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename ReturnType, typename Arg0, typename Arg1>
class CRawStaticFunctionForScript<ReturnType(Arg0,Arg1)> : public CNativeInvoker<ReturnType(Arg0,Arg1)>
{
public:
    using FunctionType=ReturnType(*)(Arg0,Arg1);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        return Function(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename Arg0, typename Arg1>
class CRawStaticFunctionForScript<void(Arg0,Arg1)> : public CNativeInvoker<void(Arg0,Arg1)>
{
public:
    using FunctionType=void(*)(Arg0,Arg1);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        Function(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2>
class CRawStaticFunctionForScript<ReturnType(Arg0,Arg1,Arg2)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=ReturnType(*)(Arg0,Arg1,Arg2);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        return Function(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename Arg0, typename Arg1, typename Arg2>
class CRawStaticFunctionForScript<void(Arg0,Arg1,Arg2)> : public CNativeInvoker<void(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=void(*)(Arg0,Arg1,Arg2);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        Function(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CRawStaticFunctionForScript<ReturnType(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=ReturnType(*)(Arg0,Arg1,Arg2,Arg3);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        return Function(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CRawStaticFunctionForScript<void(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=void(*)(Arg0,Arg1,Arg2,Arg3);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        Function(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CRawStaticFunctionForScript<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=ReturnType(*)(Arg0,Arg1,Arg2,Arg3,Arg4);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        return Function(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CRawStaticFunctionForScript<void(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=void(*)(Arg0,Arg1,Arg2,Arg3,Arg4);
    FunctionType Function;

    CRawStaticFunctionForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        Function(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RawStaticFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RawStaticFunction)
        {
            return false;
        }
        return Function==static_cast<const CRawStaticFunctionForScript*>(Other)->Function;
    }
};

template<typename RObjectType,typename ReturnType, typename ...Args>
requires (sizeof...(Args) <= 5)
class CRObjectMemberForScript;


template<typename RObjectType,typename ReturnType>
class CRObjectMemberForScript<RObjectType,ReturnType()> : public CNativeInvoker<ReturnType()>
{
public:
    using FunctionType=ReturnType(RObjectType::*)();
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke() override
    {
        return ((RObjectType*)Object.Get()->*Function)();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)());
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType>
class CRObjectMemberForScript<RObjectType,void()> : public CNativeInvoker<void()>
{
public:
    using FunctionType=void(RObjectType::*)();
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke() override
    {
        ((RObjectType*)Object.Get()->*Function)();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        ((RObjectType*)Object.Get()->*Function)();
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename ReturnType, typename Arg0>
class CRObjectMemberForScript<RObjectType,ReturnType(Arg0)> : public CNativeInvoker<ReturnType(Arg0)>
{
public:
    using FunctionType=ReturnType(RObjectType::*)(Arg0);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0) override
    {
        return ((RObjectType*)Object.Get()->*Function)(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename Arg0>
class CRObjectMemberForScript<RObjectType,void(Arg0)> : public CNativeInvoker<void(Arg0)>
{
public:
    using FunctionType=void(RObjectType::*)(Arg0);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0) override
    {
        ((RObjectType*)Object.Get()->*Function)(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        ((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename ReturnType, typename Arg0, typename Arg1>
class CRObjectMemberForScript<RObjectType,ReturnType(Arg0,Arg1)> : public CNativeInvoker<ReturnType(Arg0,Arg1)>
{
public:
    using FunctionType=ReturnType(RObjectType::*)(Arg0,Arg1);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        return ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename Arg0, typename Arg1>
class CRObjectMemberForScript<RObjectType,void(Arg0,Arg1)> : public CNativeInvoker<void(Arg0,Arg1)>
{
public:
    using FunctionType=void(RObjectType::*)(Arg0,Arg1);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        ((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename ReturnType, typename Arg0, typename Arg1, typename Arg2>
class CRObjectMemberForScript<RObjectType,ReturnType(Arg0,Arg1,Arg2)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=ReturnType(RObjectType::*)(Arg0,Arg1,Arg2);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        return ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename Arg0, typename Arg1, typename Arg2>
class CRObjectMemberForScript<RObjectType,void(Arg0,Arg1,Arg2)> : public CNativeInvoker<void(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=void(RObjectType::*)(Arg0,Arg1,Arg2);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        ((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CRObjectMemberForScript<RObjectType,ReturnType(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=ReturnType(RObjectType::*)(Arg0,Arg1,Arg2,Arg3);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        return ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CRObjectMemberForScript<RObjectType,void(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=void(RObjectType::*)(Arg0,Arg1,Arg2,Arg3);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        ((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename ReturnType, typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CRObjectMemberForScript<RObjectType,ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=ReturnType(RObjectType::*)(Arg0,Arg1,Arg2,Arg3,Arg4);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        return ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};

template<typename RObjectType,typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CRObjectMemberForScript<RObjectType,void(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=void(RObjectType::*)(Arg0,Arg1,Arg2,Arg3,Arg4);
    union
    {
        FunctionType Function;
        uint64_t FunctionHash;
    };
    TWeakObjectPtr<RObject> Object;

    CRObjectMemberForScript(FunctionType InFunction,RObject* InObject)
        :Function(InFunction)
        ,Object(InObject)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        ((RObjectType*)Object.Get()->*Function)(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::RObjectMember;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        ((RObjectType*)Object.Get()->*Function)(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return FunctionHash+(uint64_t)(Object.GetHashCode());
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::RObjectMember)
        {
            return false;
        }
        auto OtherMember=static_cast<const CRObjectMemberForScript*>(Other);
        return Function==OtherMember->Function&&Object==OtherMember->Object;
    }
};


template<typename ReturnType, typename ...Args>
requires (sizeof...(Args) <= 5)
class CLambdaForScript;


template<typename ReturnType>
class CLambdaForScript<ReturnType()> : public CNativeInvoker<ReturnType()>
{
public:
    using FunctionType=std::function<ReturnType()>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke() override
    {
        return Function();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        return CAny(Function());
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<>
class CLambdaForScript<void()> : public CNativeInvoker<void()>
{
public:
    using FunctionType=std::function<void()>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke() override
    {
        Function();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& /*InArguments*/) override
    {
        Function();
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return {};
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename ReturnType,typename Arg0>
class CLambdaForScript<ReturnType(Arg0)> : public CNativeInvoker<ReturnType(Arg0)>
{
public:
    using FunctionType=std::function<ReturnType(Arg0)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0) override
    {
        return Function(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename Arg0>
class CLambdaForScript<void(Arg0)> : public CNativeInvoker<void(Arg0)>
{
public:
    using FunctionType=std::function<void(Arg0)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0) override
    {
        Function(InArg0);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename ReturnType,typename Arg0, typename Arg1>
class CLambdaForScript<ReturnType(Arg0,Arg1)> : public CNativeInvoker<ReturnType(Arg0,Arg1)>
{
public:
    using FunctionType=std::function<ReturnType(Arg0,Arg1)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        return Function(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename Arg0, typename Arg1>
class CLambdaForScript<void(Arg0,Arg1)> : public CNativeInvoker<void(Arg0,Arg1)>
{
public:
    using FunctionType=std::function<void(Arg0,Arg1)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1) override
    {
        Function(InArg0,InArg1);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename ReturnType,typename Arg0, typename Arg1, typename Arg2>
class CLambdaForScript<ReturnType(Arg0,Arg1,Arg2)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=std::function<ReturnType(Arg0,Arg1,Arg2)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        return Function(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename Arg0, typename Arg1, typename Arg2>
class CLambdaForScript<void(Arg0,Arg1,Arg2)> : public CNativeInvoker<void(Arg0,Arg1,Arg2)>
{
public:
    using FunctionType=std::function<void(Arg0,Arg1,Arg2)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2) override
    {
        Function(InArg0,InArg1,InArg2);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename ReturnType,typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CLambdaForScript<ReturnType(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=std::function<ReturnType(Arg0,Arg1,Arg2,Arg3)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        return Function(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename Arg0, typename Arg1, typename Arg2, typename Arg3>
class CLambdaForScript<void(Arg0,Arg1,Arg2,Arg3)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3)>
{
public:
    using FunctionType=std::function<void(Arg0,Arg1,Arg2,Arg3)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3) override
    {
        Function(InArg0,InArg1,InArg2,InArg3);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename ReturnType,typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CLambdaForScript<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=std::function<ReturnType(Arg0,Arg1,Arg2,Arg3,Arg4)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    ReturnType NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        return Function(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        return CAny(Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4])));
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};

template<typename Arg0, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
class CLambdaForScript<void(Arg0,Arg1,Arg2,Arg3,Arg4)> : public CNativeInvoker<void(Arg0,Arg1,Arg2,Arg3,Arg4)>
{
public:
    using FunctionType=std::function<void(Arg0,Arg1,Arg2,Arg3,Arg4)>;
    FunctionType Function;

    CLambdaForScript(FunctionType InFunction)
        :Function(InFunction)
    {
    }

    //override native invoke
    void NativeInvoke(Arg0 InArg0,Arg1 InArg1,Arg2 InArg2,Arg3 InArg3,Arg4 InArg4) override
    {
        Function(InArg0,InArg1,InArg2,InArg3,InArg4);
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::STDFunction;
    }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {
        Function(AnyCast<Arg0>(InArguments[0]),AnyCast<Arg1>(InArguments[1]),AnyCast<Arg2>(InArguments[2]),AnyCast<Arg3>(InArguments[3]),AnyCast<Arg4>(InArguments[4]));
        return CAny();
    }

    SDecoratedType GetReturnType() const override
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return { WH::TReflectionType<Arg0>::FindOrCreateType(),WH::TReflectionType<Arg1>::FindOrCreateType(),WH::TReflectionType<Arg2>::FindOrCreateType(),WH::TReflectionType<Arg3>::FindOrCreateType(),WH::TReflectionType<Arg4>::FindOrCreateType() };
    }

    uint64_t GetHashCode() const override
    {
        return (uint64_t)(&Function);
    }

    bool IsEqual(const IScriptFunction* Other) const override
    {
        //cant compare std::function
        //all Lambda treated as different function
        return false;
    }
};




class WHENGINE_API CReflectedFunctionForScriptDelegate : public IScriptFunction
{
public:
    TWeakObjectPtr<RObject> Object;
    CFunction* Function;

    CReflectedFunctionForScriptDelegate(TWeakObjectPtr<RObject> InObject,CFunction* InFunction)
        :Object(InObject)
        ,Function(InFunction)
    {
    }

    virtual bool SupportNativeInvoke() const override { return false; }

    CAny Invoke(const TVector<CAny>& InArguments) override
    {

        if(Function->IsStatic())
        {
            return Function->Invoke(InArguments);
        }
        else if (Object.IsValid())
        {
            TVector<CAny> Arguments;
            Arguments.Reserve(1+InArguments.Num());
            Arguments.Add(Object.Lock());
            Arguments.Append(InArguments);
            return Function->Invoke(Arguments);
        }
        return CAny();
    }

    IScriptFunction::EType GetType() const override
    {
        return IScriptFunction::EType::ReflectedFunction;
    }

    SDecoratedType GetReturnType() const override
    {
        return Function->GetReturnType();
    }

    TVector<SDecoratedType> GetParameterTypes() const override
    {
        return Function->GetParameterTypes();
    }

    uint64_t GetHashCode() const override
    {
        return WH::HashCombine(Object.GetHashCode(),(uint64_t)Function);
    }

    bool IsEqual(const IScriptFunction * Other) const override
    {
        if(Other->GetType()!=IScriptFunction::EType::ReflectedFunction)
        {
            return false;
        }
        auto OtherReflectedFunction=static_cast<const CReflectedFunctionForScriptDelegate*>(Other);
        return Object==OtherReflectedFunction->Object && Function==OtherReflectedFunction->Function;
    }

    bool IsValid() const override
    {
        return Object.IsValid() || Function->IsStatic() ;
    }
};


struct WHENGINE_API SScriptFunctionBinding
{
    std::shared_ptr<IScriptFunction> Function;

    //is bound a valid function
    bool IsValid() const
    {
        if(!Function)
        {
            return false;
        }
        return Function->IsValid();
    }

    uint64_t GetHashCode() const
    {
        return Function->GetHashCode();
    }

    bool operator==(const SScriptFunctionBinding& Other) const
    {
        if(Function->GetType()!=Other.Function->GetType())
        {
            return false;
        }
        return Function->IsEqual(Other.Function.get());
    }

    CAny ScriptInvoke(const TVector<CAny>& InArguments)
    {
        return Function->Invoke(InArguments);
    }
};


struct WHENGINE_API SScriptDelegateBase
{
public:
    TVector<SScriptFunctionBinding> Bindings;
    CFunctionTypeGeneralized* FunctionType;

    SScriptDelegateBase()=delete;

    SScriptDelegateBase(CFunctionTypeGeneralized* InFunctionType)
    {
        FunctionType=InFunctionType;
    }

    SScriptFunctionBinding Bind(TSharedObjectPtr<RObject> InObject ,CFunction* InFunction)
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CReflectedFunctionForScriptDelegate>(InObject,InFunction);
        Bindings.Add(Binding);
        return Binding;
    }


    void Bind(const SScriptFunctionBinding& Binding)
    {
        Bindings.Add(Binding);
    }

    void Unbind(const SScriptFunctionBinding& Binding)
    {
        Bindings.Remove(Binding);
    }

    bool IsBound() const
    {
        for(auto& Binding:Bindings)
        {
            if(Binding.IsValid())
            {
                return true;
            }
        }
        return false;
    }

    void Clear()
    {
        Bindings.Clear();
    }

    void Append(const SScriptDelegateBase& Other)
    {
        Bindings.Append(Other.Bindings);
    }

    CAny ScriptInvoke(const TVector<CAny>& InArguments);

    uint64_t GetHashCode() const
    {
        return Bindings.GetHashCode();
    }

    bool IsEqual(const SScriptDelegateBase& Other) const
    {
        return Bindings==Other.Bindings;
    }

protected:
    friend class  CScriptDelegateGenerialized;

    static SScriptDelegateBase* AddFunction(
        SScriptDelegateBase* Delegate
        ,TSharedObjectPtr<RObject> InObject
        ,CFunction* InFunction)
    {
        SScriptDelegateBase* Result=new SScriptDelegateBase(Delegate->FunctionType);
        Result->Bindings.Append(Delegate->Bindings);
        Result->Bind(InObject,InFunction);
        return Result;
    }

    static SScriptDelegateBase* RemoveFunction(
        SScriptDelegateBase* Delegate
        ,TSharedObjectPtr<RObject> InObject
        ,CFunction* InFunction)
    {
        SScriptDelegateBase* Result=new SScriptDelegateBase(Delegate->FunctionType);
        Result->Bindings.Append(Delegate->Bindings);
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CReflectedFunctionForScriptDelegate>(InObject,InFunction);
        Result->Bindings.Remove(Binding);
        return Result;
    }
    
    static SScriptDelegateBase* Append(SScriptDelegateBase* A,SScriptDelegateBase* B)
    {
        SScriptDelegateBase* Result=new SScriptDelegateBase(A->FunctionType);
        Result->Bindings.Append(A->Bindings);
        Result->Bindings.Append(B->Bindings);
        return Result;
    }

    //remove all bindings in B from A
    static SScriptDelegateBase* Remove(SScriptDelegateBase* A,SScriptDelegateBase* B)
    {
        SScriptDelegateBase* Result=new SScriptDelegateBase(A->FunctionType);
        Result->Bindings.Append(A->Bindings);
        for(auto& Binding:B->Bindings)
        {
            Result->Bindings.Remove(Binding);
        }
        return Result;
    }

};

//multi cast delegate
//can both be used in c++ and script
template< typename ReturnType, typename ...Args>
requires (sizeof...(Args) <= 5)
struct TScriptDelegate<ReturnType(Args...)> :  public SScriptDelegateBase
{
public:
    TScriptDelegate()
    : SScriptDelegateBase(
        reinterpret_cast<CFunctionTypeGeneralized*>(
            WH::TReflectionType<ReturnType(Args...)>::FindOrCreateType()
        )
    )
    {
    }

    //for invoke in c++
    ReturnType Broadcast(Args... InArguments)
    {
        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
                
            if(!Binding.IsValid())
            {
                Bindings.Remove(Binding);
                i--;
                continue;
            }
        }

        if(Bindings.Num()==0)
        {
            return ReturnType();
        }

        //have reflection binding
        bool bHasReflectionBinding=false;
        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
            if(!Binding.Function->SupportNativeInvoke())
            {
                bHasReflectionBinding=true;
                break;
            }
        }

        if(bHasReflectionBinding)
        {
            TVector<CAny> Arguments={CAny(InArguments)...};
            for(int i=0;i<Bindings.Num();i++)
            {
                auto& Binding=Bindings[i];
                if(!Binding.Function->SupportNativeInvoke())
                {
                    if(i==Bindings.Num()-1)
                    {
                        //last one
                        return AnyCast<ReturnType>(Binding.ScriptInvoke(Arguments));
                    }
                    else
                    {
                        Binding.ScriptInvoke(Arguments);
                    }
                }
                else
                {
                    if(i==Bindings.Num()-1)
                    {
                        //last one
                        return static_cast<CNativeInvoker<ReturnType(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
                    }
                    else
                    {
                        static_cast<CNativeInvoker<ReturnType(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
                    }
                }
            }

            assert(false && "should not reach here");
        }

        //no reflection binding
        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
            if(i==Bindings.Num()-1)
            {
                //last one
                return static_cast<CNativeInvoker<ReturnType(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
            }
            else
            {
                static_cast<CNativeInvoker<ReturnType(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
            }
        }

        assert(false && "should not reach here");
        return ReturnType();
    }

    SDecoratedType GetReturnType() const 
    {
        return WH::TReflectionType<ReturnType>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const 
    {
        return { WH::TReflectionType<Args>::FindOrCreateType()... };
    }

    //bind a lambda function, return a binding
    //you can use this binding to unbind the function
    //if you bind a lambda  twice, it will be treated as two different function
    SScriptFunctionBinding BindLambda(std::function<ReturnType(Args...)> InFunction)
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CLambdaForScript<ReturnType(Args...)>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    } 

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(RObjectType* InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        //find function
        CFunction* Function=InObject->GetClass()->FindNativeFunction(*(int64_t*)(&InFunction));
        if(!Function)
        {
            return SScriptFunctionBinding();
        }

        //bind a reflected function
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CReflectedFunctionForScriptDelegate>(InObject,Function);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TSharedObjectPtr<RObjectType> InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        return BindScript(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TWeakObjectPtr<RObjectType> InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        return BindScript(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(RObjectType* InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRObjectMemberForScript<RObjectType,ReturnType(Args...)>>(InFunction,InObject);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TSharedObjectPtr<RObjectType> InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        return Bind(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TWeakObjectPtr<RObjectType> InObject ,ReturnType(RObjectType::*InFunction)(Args...))
    {
        return Bind(InObject.Get(),InFunction);
    }

    SScriptFunctionBinding BindRawStaticFunction(ReturnType(*InFunction)(Args...))
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRawStaticFunctionForScript<ReturnType(Args...)>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    }


};
static_assert(sizeof(TScriptDelegate<int(int,double)>)==sizeof(SScriptDelegateBase),"TScriptDelegate must have same size as SScriptDelegateBase for script use");

template<typename ...Args>
requires (sizeof...(Args) <= 5)
struct TScriptDelegate<void(Args...)> :  public SScriptDelegateBase
{
public:
    TScriptDelegate()
    : SScriptDelegateBase(
        reinterpret_cast<CFunctionTypeGeneralized*>(
            WH::TReflectionType<void(Args...)>::FindOrCreateType()
        )
    )
    {
    }

    //for invoke in c++
    void Broadcast(Args... InArguments)
    {
        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
                
            if(!Binding.IsValid())
            {
                Bindings.Remove(Binding);
                i--;
                continue;
            }
        }

        if(Bindings.Num()==0)
        {
            return;
        }

        //have reflection binding
        bool bHasReflectionBinding=false;

        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
            if(!Binding.Function->SupportNativeInvoke())
            {
                bHasReflectionBinding=true;
                break;
            }
        }

        if(bHasReflectionBinding)
        {
            TVector<CAny> Arguments={CAny(InArguments)...};

            //复制一份，因为在调用过程中可能会修改Bindings
            //甚至可能会删除Bindings
            auto CachedBindings=Bindings;
            for(int i=0;i<CachedBindings.Num();i++)
            {
                auto& Binding=CachedBindings[i];
                if(!Binding.Function->SupportNativeInvoke())
                {
                    Binding.ScriptInvoke(Arguments);
                }
                else
                {
                    static_cast<CNativeInvoker<void(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
                }
            }

            return;
        }

        //no reflection binding
        auto CachedBindings=Bindings;
        for(int i=0;i<CachedBindings.Num();i++)
        {
            auto& Binding=CachedBindings[i];
            static_cast<CNativeInvoker<void(Args...)>*>(Binding.Function.get())->NativeInvoke(InArguments...);
        }

        return;
    }

    SDecoratedType GetReturnType() const 
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const 
    {
        return { WH::TReflectionType<Args>::FindOrCreateType()... };
    }

    //bind a lambda function, return a binding
    //you can use this binding to unbind the function
    //if you bind a lambda  twice, it will be treated as two different function
    SScriptFunctionBinding BindLambda(std::function<void(Args...)> InFunction)
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CLambdaForScript<void(Args...)>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    } 

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(RObjectType* InObject ,void(RObjectType::*InFunction)(Args...))
    {
        //find function
        CFunction* Function=InObject->GetClass()->FindNativeFunction(*(int64_t*)(&InFunction));
        if(!Function)
        {
            return SScriptFunctionBinding();
        }

        //bind a reflected function
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CReflectedFunctionForScriptDelegate>(InObject,Function);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TSharedObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)(Args...))
    {
        return BindScript(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TWeakObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)(Args...))
    {
        return BindScript(InObject.Get(),InFunction);
    } 


    template<typename RObjectType>
    SScriptFunctionBinding Bind(RObjectType* InObject ,void(RObjectType::*InFunction)(Args...))
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRObjectMemberForScript<RObjectType,void(Args...)>>(InFunction,InObject);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TSharedObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)(Args...))
    {
        return Bind(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TWeakObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)(Args...))
    {
        return Bind(InObject.Get(),InFunction);
    } 

    SScriptFunctionBinding BindRawStaticFunction(void(*InFunction)(Args...))
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRawStaticFunctionForScript<void(Args...)>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    }
};

static_assert(sizeof(TScriptDelegate<void(int,double)>)==sizeof(SScriptDelegateBase),"TScriptDelegate must have same size as SScriptDelegateBase for script use");

//specialization for void()
template<>
struct TScriptDelegate<void()> :  public SScriptDelegateBase
{
public:
    TScriptDelegate()
    : SScriptDelegateBase(
        reinterpret_cast<CFunctionTypeGeneralized*>(
            WH::TReflectionType<void()>::FindOrCreateType()
        )
    )
    {
    }

    //for invoke in c++
    void Broadcast()
    {
        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
                
            if(!Binding.IsValid())
            {
                Bindings.Remove(Binding);
                i--;
                continue;
            }
        }

        if(Bindings.Num()==0)
        {
            return;
        }

        //have reflection binding
        bool bHasReflectionBinding=false;

        for(int32_t i=0;i<Bindings.Num();i++)
        {
            auto& Binding=Bindings[i];
            if(!Binding.Function->SupportNativeInvoke())
            {
                bHasReflectionBinding=true;
                break;
            }
        }

        if(bHasReflectionBinding)
        {
            TVector<CAny> Arguments;
            auto CachedBindings=Bindings;
            for(int i=0;i<CachedBindings.Num();i++)
            {
                auto& Binding=CachedBindings[i];
                if(!Binding.Function->SupportNativeInvoke())
                {
                    Binding.ScriptInvoke(Arguments);
                }
                else
                {
                    static_cast<CNativeInvoker<void()>*>(Binding.Function.get())->NativeInvoke();
                }
            }

            return;
        }

        //no reflection binding
        auto CachedBindings=Bindings;
        for(int i=0;i<CachedBindings.Num();i++)
        {
            auto& Binding=CachedBindings[i];
            static_cast<CNativeInvoker<void()>*>(Binding.Function.get())->NativeInvoke();
        }

        return;
    }

    SDecoratedType GetReturnType() const 
    {
        return WH::TReflectionType<void>::FindOrCreateType();
    }

    TVector<SDecoratedType> GetParameterTypes() const 
    {
        return {};
    }

    //bind a lambda function, return a binding
    //you can use this binding to unbind the function
    //if you bind a lambda  twice, it will be treated as two different function
    SScriptFunctionBinding BindLambda(std::function<void()> InFunction)
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CLambdaForScript<void()>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(RObjectType* InObject ,void(RObjectType::*InFunction)())
    {
        //find function
        CFunction* Function=InObject->GetClass()->FindNativeFunction(*(int64_t*)(&InFunction));
        if(!Function)
        {
            return SScriptFunctionBinding();
        }

        //bind a reflected function
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CReflectedFunctionForScriptDelegate>(InObject,Function);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TSharedObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)())
    {
        return BindScript(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding BindScript(TWeakObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)())
    {
        return BindScript(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(RObjectType* InObject ,void(RObjectType::*InFunction)())
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRObjectMemberForScript<RObjectType,void()>>(InFunction,InObject);
        Bindings.Add(Binding);
        return Binding;
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TSharedObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)())
    {
        return Bind(InObject.Get(),InFunction);
    }

    template<typename RObjectType>
    SScriptFunctionBinding Bind(TWeakObjectPtr<RObjectType> InObject ,void(RObjectType::*InFunction)())
    {
        return Bind(InObject.Get(),InFunction);
    }

    SScriptFunctionBinding BindRawStaticFunction(void(*InFunction)())
    {
        SScriptFunctionBinding Binding;
        Binding.Function=std::make_shared<CRawStaticFunctionForScript<void()>>(InFunction);
        Bindings.Add(Binding);
        return Binding;
    }

};

static_assert(sizeof(TScriptDelegate<void()>)==sizeof(SScriptDelegateBase),"TScriptDelegate must have same size as SScriptDelegateBase for script use");